<template>
    <div class="QilinForm">
        <el-form
            ref="QilinFormRef"
            :model="ownFormConfig.submitData"
            :rules="ownFormRules"
            :label-position="(ownFormConfig.elFormConfig && ownFormConfig.elFormConfig.labelPosition) || 'right' "
            :label-width="(ownFormConfig.elFormConfig && ownFormConfig.elFormConfig.labelWidth) || '60px' "
            :size="(ownFormConfig.elFormConfig && ownFormConfig.elFormConfig.size) || 'small' "
            :class="ownFormConfig.elFormConfig ? ownFormConfig.elFormConfig.className : '' "
        >
            <template v-for="(item,index) in ownFormConfig.itemConfig">
                <el-form-item
                    v-if="!item.isHide && item.type !== 'itemSlot' "
                    :key="item.dataName || 'form-key-'+index "
                    :prop="item.dataName"
                    :style="item.itemStyle"
                    :class="[
                        'width'+(item.width ? item.width : 24),
                        item.className
                    ]"
                >
                    <template v-slot:label>
                        {{
                            item.hideLabel ? "" :
                            item.labelName ? item.labelName + ((ownFormConfig.elFormConfig && ownFormConfig.elFormConfig.labelSuffix) || "：") :
                            "默认名称"+index
                        }}
                        <span v-if="item.labelNameText">{{item.labelNameText || ""}}</span>
                    </template>
                    <template v-if="item.type === 'input' || !item.type ">
                        <el-input
                            v-model="ownFormConfig.submitData[item.dataName]"
                            v-number:[item]="item.number"
                            :type="item.inputType || 'text' "
                            :clearable="item.clearable === false ? false : true"
                            :disabled="item.disabled || false "
                            :placeholder="item.placeholder || '请输入'+item.labelName "
                            :show-password="item.showPassword || false "
                            :rows="item.rows || 2 "
                            :auto-complete="
                                item.autocomplete ? item.autocomplete :
                                item.inputType === 'password' ? 'new-password' : 'new-text'
                            "
                            :prefix-icon="item.prefixIcon"
                            :suffix-icon="item.suffixIcon"
                            :maxlength="item.maxlength"
                            :minlength="item.minlength"
                            :show-word-limit="['text','textarea'].includes(item.inputType)"
                            :style="item.style"
                            @input="(val)=>{
                                synchronous('input',item,val);
                            }"
                            @blur="(event)=>{
                                synchronous('blur',item,event);
                            }"
                            @clear="()=>{
                                synchronous('clear',item);
                            }"
                        >
                            <template v-slot:prefix>
                                <slot :name="item.prefixSlotName" :data="{data:ownFormConfig.submitData[item.dataName],item}"></slot>
                            </template>
                            <template v-slot:suffix>
                                <slot :name="item.suffixSlotName" :data="{data:ownFormConfig.submitData[item.dataName],item}"></slot>
                            </template>
                        </el-input>
                    </template>
                    <template v-else-if="item.type === 'number' ">
                        <el-input-number
                            v-model="ownFormConfig.submitData[item.dataName]"
                            :disabled="item.disabled || false"
                            :max="item.max || Infinity"
                            :min="item.min === undefined ? -Infinity : item.min"
                            :controls-position="item.controlsPosition || ''"
                        ></el-input-number>
                    </template>
                    <template v-else-if="item.type === 'select' ">
                        <el-select
                            v-model="ownFormConfig.submitData[item.dataName]"
                            :clearable="item.clearable === false ? false : true "
                            :disabled="item.disabled || false "
                            :placeholder="item.placeholder || '请选择'+item.labelName "
                            :multiple="item.multiple || false "
                            :collapse-tags="item.collapseTags || false"
                            :filterable="item.filterable === false ? false : true"
                            :loading="item.loading || false"
                            :remote="item.remote || false"
                            :remote-method="item.remoteMethod"
                            :validate-event="false"
                            :style="item.style"
                            @blur="(event)=>{
                                synchronous('blur',item,event);
                            }"
                            @change="(val)=>{
                                synchronous('change',item,val);
                            }"
                            @clear="()=>{
                                synchronous('clear',item);
                            }"
                        >
                            <template
                                v-for="optItem in ownFormConfig.selectLists[item.dataListName]"
                            >
                                <el-option
                                    :key="[null,undefined].includes(optItem.value) ? optItem[item.customValueName] : optItem.value"
                                    :disabled="optItem.disabled || false "
                                    :label="[null,undefined].includes(optItem.label) ? optItem[item.customLabelName] : optItem.label"
                                    :value="[null,undefined].includes(optItem.value) ? optItem[item.customValueName] : optItem.value"
                                ></el-option>
                            </template>
                        </el-select>
                    </template>
                    <template v-else-if="item.type === 'cascader' ">
                        <el-cascader
                            ref="cascaderRef"
                            v-model="ownFormConfig.submitData[item.dataName]"
                            :placeholder="item.placeholder || '请选择'+item.labelName "
                            :options="ownFormConfig.selectLists[item.dataListName] || [] "
                            :props="item.cascaderProps"
                            :disabled="item.disabled || false "
                            :style="item.style"
                            @change="(val)=>{
                                synchronous('change',item,val)
                            }"
                        ></el-cascader>
                    </template>
                    <template v-else-if="item.type === 'radio' ">
                        <el-radio-group
                            v-model="ownFormConfig.submitData[item.dataName]"
                            :disabled="item.disabled || false "
                            :style="item.style"
                            @input="(val)=>{
                                synchronous('input',item,val)
                            }"
                        >
                            <template
                                v-for="optItem in ownFormConfig.selectLists[item.dataListName]"
                            >
                                <el-radio
                                    v-if="!optItem.isHide"
                                    :key="[null,undefined].includes(optItem.label) ? optItem[item.customLabelName] : optItem.label"
                                    :label="[null,undefined].includes(optItem.label) ? optItem[item.customLabelName] : optItem.label"
                                    :disabled="optItem.disabled || false "
                                >{{[null,undefined].includes(optItem.label) ? optItem[item.customLabelName] : optItem.label}}</el-radio>
                            </template>
                        </el-radio-group>
                    </template>
                    <template v-else-if="item.type === 'switch' ">
                        <el-switch
                            v-model="ownFormConfig.submitData[item.dataName]"
                            :disabled="item.disabled || false "
                            :active-text="item.activeText || '' "
                            :inactive-text="item.inactiveText || '' "
                            :active-value="[null,undefined].includes(item.activeValue) ? true : item.activeValue "
                            :inactive-value="[null,undefined].includes(item.inactiveValue) ? true : item.inactiveValue "
                            :style="item.style"
                            @change="(val)=>{
                                synchronous('change',item,val);
                            }"
                        ></el-switch>
                    </template>
                    <template v-else-if="item.type === 'date' ">
                        <el-date-picker
                            v-model="ownFormConfig.submitData[item.dataName]"
                            :type="item.dateType || 'date' "
                            :placeholder="
                                !(item.dateType && item.dateType.includes('range')) ? (item.placeholder || '请选择'+item.labelName) : ''
                            "
                            :start-placeholder="
                                (item.dateType && item.dateType.includes('range')) ? item.startPlaceholder || '开始时间' : ''
                            "
                            :end-placeholder="
                                (item.dateType && item.dateType.includes('range')) ? item.endPlaceholder || '结束时间' : ''
                            "
                            :format="item.format || 'yyyy-MM-dd' "
                            :value-format="item.valueFormat || 'yyyy-MM-dd' "
                            :range-separator="item.rangeSeparator || '至' "
                            :default-time="
                                item.defaultTime ||
                                ((item.dateType && item.dateType.includes('range')) ? ['08:30:00','17:30:00'] : '08:30:00')
                            "
                            :style="`width:${item.dateWidth ? item.dateWidth : (item.dateType && item.dateType.includes('range')) ? 280+'px' : ''};`"
                            placement="bottom-start"
                            @blur="(event)=>{
                                synchronous('blur',item,event)
                            }"
                            @change="(val)=>{
                                synchronous('change',item,val)
                            }"
                        ></el-date-picker>
                    </template>
                    <template v-else-if="item.type === 'checkbox' ">
                        <el-checkbox-group
                            v-model="ownFormConfig.submitData[item.dataName]"
                            :style="item.style"
                            @change="(val)=>{
                                synchronous('change',item,val);
                            }"
                        >
                            <el-checkbox
                                v-for="optItem in ownFormConfig.selectLists[item.dataListName]"
                                :key="[null,undefined].includes(optItem.label) ? optItem[item.customLabelName] : optItem.label"
                                :label="[null,undefined].includes(optItem.label) ? optItem[item.customLabelName] : optItem.label"
                                :disabled="optItem.disabled || false "
                            >{{[null,undefined].includes(optItem.label) ? optItem[item.customLabelName] : optItem.label}}</el-checkbox>
                        </el-checkbox-group>
                    </template>
                    <template v-else-if="item.type === 'upload' ">
                        <QilinUploadFile
                            :uploadFileConfig.sync="ownFormConfig.itemConfig[index]"
                            :fileList="ownFormConfig.submitData[item.dataName]"
                            @success="(fileList)=>{
                                ownFormConfig.submitData[item.dataName]=fileList;
                                synchronous('customFn',item,file);
                                formClearValidate(item.dataName);
                            }"
                            @actionSuccess="(res,file)=>{
                                ownFormConfig.submitData[item.dataName].push({...res[(item.fileOptions && item.fileOptions.responseDataName) || 'data'],raw:file.raw});
                                formClearValidate(item.dataName);
                            }"
                        ></QilinUploadFile>
                    </template>
                    <template v-else-if="item.type === 'image' ">
                        <QilinUploadImage
                            :uploadImageConfig.sync="ownFormConfig.itemConfig[index]"
                            :fileList="ownFormConfig.submitData[item.dataName]"
                            @success="(fileList,file)=>{
                                ownFormConfig.submitData[item.dataName]=fileList;
                                synchronous('customFn',item,file);
                                formClearValidate(item.dataName);
                            }"
                            @actionSuccess="(res,file)=>{
                                ownFormConfig.submitData[item.dataName].push({...res[(item.imageOptions && item.imageOptions.responseDataName) || 'data'],raw:file.raw});
                                formClearValidate(item.dataName);
                            }"
                        ></QilinUploadImage>
                    </template>
                    <template v-else-if="item.type === 'slot' ">
                        <slot
                            :name="item.slotName"
                            :data="{item}"
                        ></slot>
                    </template>
                </el-form-item>
                <slot v-if="item.type === 'itemSlot'" :name="item.slotName" :data="{item}"></slot>
            </template>
            <slot name="extraFormItem"></slot>
            <el-form-item
                :class="['QilinForm-button',ownFormConfig.buttonConfigClassName]"
                v-if="ownFormConfig.buttonConfig && ownFormConfig.buttonConfig.length > 0 "
            >
                <template
                    v-for="(item,index) in ownFormConfig.buttonConfig"
                >
                    <el-button
                        :key="item.btnName+index"
                        :type="item.btnType || 'primary' "
                        :size="item.btnSize || 'small' "
                        :class="item.className"
                        v-bind="item"
                        @click="item.btnClick && item.btnClick(item.formRefName && item.formRefName(),$event)"
                    >{{item.btnName || "按钮"}}</el-button>
                </template>
            </el-form-item>
        </el-form>
        <slot name="extraItem"></slot>
    </div>
</template>

<script>
import QilinFormRules from "./formRules.js";
export default {
    name:"QilinForm",
    props:{
        formConfig:{
            type:Object,
            default(){
                return {
                    // el-form标签上的相关配置
                    elFormConfig:{
                        labelPosition:"right", //label对齐方式--默认right
                        labelWidth:"60px", //label宽度--默认60px
                        size:"small", //el-form的大小--默认small
                        className:"", //el-form的自定义类名
                    },
                    // 表单结构相关配置项
                    itemConfig:[
                        {
                            dataName:"name", //对应后台数据名
                            labelName:"姓名", //label名称
                            isHide:false, //是否隐藏该表单项
                            hideLabel:false, //是否隐藏label字段
                            labelNameText:"", //label标签的额外字段
                            type:"input", //表单组件类型--默认为input
                            inputType:"text", //表单input类型--默认为text--仅当type为input时生效
                            showPassword:false, //是是否显示切换密码图标，当且仅当inputType=password时生效
                            autocomplete:"off", //点击密码框是否提示快捷密码，默认off不提示
                            clearable:true, //是否可以一键清空--默认true
                            rows:2, //行高--默认2--当inputType为textarea生效
                            number:"", //当输入框为数字输入框时，允许输入的整数位数，当inputType为number时生效
                            decimal:"", //当输入框为数字输入框时，允许输入的小数位数，当inputType为number时生效
                            negativeSign:false, //当输入框为数字输入框时，表示是否支持负数，默认不支持，当inputType为number时生效
                            maxlength:"", //最大输入长度
                            minlength:"", //最小输入长度
                            prefixIcon:"", //输入框前置内置图标
                            prefixSlotName:"", //输入框前置内置图标插槽名称
                            suffixIcon:"", //输入框后置内置图标
                            suffixSlotName:"", //输入框后置内置图标插槽名称
                            max:"", //最大输入数字
                            min:"", //最小输入数字
                            controlsPosition:"", //数字输入框的控制按钮位置
                            dataListName:"", //下拉数据名对应selectLists中属性--当type为select时生效
                            multiple:false, //是否可以多选--当type为select、checkbox时生效默认false
                            collapseTags:false, //多选时是否将选中值按文字的形式展示--默认false--当type为select时生效
                            filterable:true, //是否可搜索--默认true--当type为select时生效
                            cascaderProps:{}, //配置级联选择器的选项，当type为cascader时生效，里面的参数详见element官网文档
                            loadMore:"event", //下拉滚动加载事件--当type为select时生效
                            customLabelName:"label", //下拉选项中自定义label对应字段值，默认label--当type为select、radio、checkbox时生效
                            customValueName:"value", //下拉选项中自定义value对应字段值，默认value--当type为select、radio、checkbox时生效
                            selectOptionValueName:"value", //下拉选项中的value对应的字段名，默认为value，旧版本不推荐
                            selectOptionLabelName:"label", //下拉选项中的label对应的字段名，默认为label，旧版本不推荐
                            loading:false, //是否正在从远程获取数据，当type为select时生效
                            remote:false, //其中的选项是否从服务器远程加载，当type为select时生效
                            remoteMethod:"event", //自定义远程搜索方法
                            dateType:"date", //时间选择器类型--默认为date--当type为date时生效
                            defaultTime:"08:30:00", // 当选择时间时默认选中的时分秒时刻，默认8点半
                            format:"yyyy-MM-dd", //时间格式化配置--默认yyyy-MM-dd--当type为date时生效
                            valueFormat:"yyyy-MM-dd", //时间格式化配置--默认yyyy-MM-dd--当type为date时生效
                            startPlaceholder:"", //日期开始提示语--当type为date时生效
                            endPlaceholder:"", //日期结束提示语--当type为date时生效
                            rangeSeparator:"至", //时间选择器的范围分隔符
                            activeText:"", //switch打开时的文字描述
                            inactiveText:"", //switch关闭时的文字描述
                            activeValue:true, //switch状态为on时的值
                            inactiveValue:false, //switch状态为off时的值
                            inlinePrompt:false, //switch时图标或文字是否显示在开关内
                            width:24, //表单item的栅栏占比宽度--默认24
                            className:"", //el-form-item的自定义类名
                            disabled:false, //是否禁用--默认false
                            placeholder:"", //表单提示语
                            slotName:"", //slot具名插槽名称
                            style:"", //额外行内样式
                            itemStyle:"", //额外的el-form-item的样式
                            change:"event", //change事件
                            clear:"event", //clear事件
                            dateWidth:'auto', //元素的长度，默认为220px，当type=date时生效
                        }
                    ],
                    // 下拉数据集
                    selectLists:{},
                    // 表单底部操作提交按钮相关配置项
                    buttonConfig:[
                        {
                            btnName:"按钮", //按钮名称
                            btnType:"primary", //按钮类型
                            btnSize:"small", //按钮大小
                            className:"", //按钮自定义类名
                            formRefName:"event", //因为生命周期的原因，故该属性接收一个用以返回DOM元素的方法
                            btnClick:"event" //点击事件
                        }
                    ],
                    buttonConfigClassName:"", //表单底部按钮自定义类名
                    // 提交到后台的数据集
                    submitData:{}
                }
            }
        }
    },
    data(){
        return {

        }
    },
    computed:{
        ownFormConfig:{
            get(){
                return this.formConfig;
            },
            set(val){
                this.$emit("update:formConfig",val);
            }
        }
    },
    methods:{
        // 创建表单的校验规则
        createFormRules(){
            let ruleObj={};
            this.ownFormConfig.itemConfig.forEach((item)=>{
                if(item.validate && item.validate.length>0){
                    ruleObj[item.dataName]=item.validate;
                };
                if(item.otherValidate){
                    if(ruleObj[item.dataName] && ruleObj[item.dataName].length>0){
                        ruleObj[item.dataName]=ruleObj[item.dataName].concat(QilinFormRules[item.otherValidate]);
                    }else{
                        ruleObj[item.dataName]=QilinFormRules[item.otherValidate];
                    };
                };
            });
            this.ownFormRules=ruleObj;
        },
        // 触发表单元素定义事件
        synchronous(eventType,item,e,ref){
            // console.log(eventType,item,e);
            item[eventType] && item[eventType](item,e);
        },
        // 调用el-form表单组件的校验事件监听
        formValidate(callback){
            this.$refs["QilinFormRef"].validate((valid)=>{
                if(callback){
                    callback(valid);
                };
            });
        },
        // 调用el-form表单组件的单字段校验事件监听
        formValidateField(dataName,callback){
            this.$refs["QilinFormRef"].validateField(dataName,(valid)=>{
                if(callback){
                    callback(valid);
                };
            });
        },
        // 调用el-form表单组件的清空校验事件监听
        formResetFields(){
            this.$nextTick(()=>{ //防止关闭弹窗会触发表单的校验事件
                this.$refs["QilinFormRef"].resetFields();
                this.ownFormConfig.itemConfig.forEach((item)=>{
                    if(item.type === "image" || item.type === "upload"){
                        item.fileList=[];
                        this.ownFormConfig.submitData[item.dataName]=[];
                    }else if(item.type === "number"){
                        this.ownFormConfig.submitData[item.dataName]=item.min;
                    }else if(item.type === "checkbox"){
                        this.ownFormConfig.submitData[item.dataName]=[];
                    }else{
                        this.ownFormConfig.submitData[item.dataName]="";
                    };
                });
            });
        },
        // 调用el-form表单组件的单字段清除校验事件监听
        formClearValidate(dataName){
            this.$refs["QilinFormRef"].clearValidate(dataName || "");
        }
    },
    created(){
        this.createFormRules();
    },
    mounted(){

    }
}
</script>

<style lang="scss" scoped>
.QilinForm{
    width:100%;
    :deep(>.el-form){
        overflow:hidden;
        :deep(.hideLabel>.el-form-item__label){
            display:none;
        }
        >.el-form-item{
            float:left;
            >.el-form-item__label{
                >span{
                    background-color:rgba(20,142,255,0.15);
                    font-size:$small-text-size;
                    padding:4px 6px;
                    border-radius:$radius-mini;
                    cursor:context-menu;
                }
            }
        }
        >.width24{
            width:100%;
        }
        >.width18{
            width:75%;
        }
        >.width16{
            width:66.66%;
        }
        >.width12{
            width:50%;
        }
        >.width8{
            width:33.33%;
        }
        >.width6{
            width:25%;
        }
        >.el-form-item.QilinForm-button{
            width:100%;
            :deep(.el-form-item__content){
                // margin-left:0!important;
                text-align:center;
            }
        }
        .el-select{
            width:100%;
        }
        .el-textarea__inner{
            font-family: inherit ;
        }
    }
}
</style>
